
from typing import Dict

import re


import ujson
from parsel import Selector
from urllib.parse import urljoin as _urljoin
from bald_spider.exceptions import DecodeError
from bald_spider.http.request import Request


class Response:
    def __init__(
            self, url: str, *,
            headers: Dict,
            body: bytes = b"",
            request: Request,
            status: int = 200,

    ):
        self.url = url
        self.headers = headers
        self.body = body
        self.request = request
        self.status = status
        self.encoding = request.encoding
        self._text_cache = None
        self._json_cache = None
        self._selector = None

    @property
    def text(self):
        if self._text_cache:
            return self._text_cache
        try:
            self._text_cache = self.body.decode(self.encoding)
        except UnicodeDecodeError:
            try:
                _encoding_re = re.compile(r"charset=([\w-]+)", flags=re.I)
                _encoding_str = self.headers.get("Content-Type", '') or self.headers.get("content-type", '')
                _encoding = _encoding_re.search(_encoding_str)
                if _encoding:
                    self.encoding = _encoding.group(1)
                    self._text_cache = self.body.decode(self.encoding)
                else:
                    raise DecodeError(f"{self.request} {self.request.encoding} error.")
            except UnicodeDecodeError as e:
                raise UnicodeDecodeError(e.encoding,e.object,e.start,e.end,f"{self.request}")
        return self._text_cache

    def json(self):
        if self._json_cache:
            return self._json_cache
        self._json_cache = ujson.loads(self.text)
        return self._json_cache

    def xpath(self,xpath_str):
        if self._selector is None:
            self._selector = Selector(self.text)
        return self._selector.xpath(xpath_str)

    def urljoin(self,url):
        return _urljoin(self.url, url)

    def __str__(self):
        return f"{self.status} {self.url}"

    @property
    def meta(self):
        return self.request.meta
